package de.dqi.pong;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.util.ArrayList;

import de.dqi.pong.engine.AI;


/**
 * TODO AILoader - finish class definition
 * <hr>
 * 
 * <hr><dl><dt>
 * Summary: </dt><br><dd>
 *  
 * </dd><br><dt>
 * Author: </dt><br><dd>
 *  Vincent
 * </dd></dl>
 */
public class AILoader {
	
	public static final String	LOAD_PACKAGE	= "ai";
	public static final String	LOAD_PATH		= System.getProperty("user.dir");
	
	/**
	 * Used to test the functionality of AILoader.
	 * <hr>
	 * @param args - The parameters provided on Program call
	 */
	public static void main(String[] args) {
		System.out.println(LOAD_PATH);
		System.out.println(System.getProperty("user.home"));
		
		AILoader.getLoadedAIs();
		for (int i = 0; i < loadedAIs.length; i++) {
			System.out.println(loadedAINames[i]);
			System.out.println(loadedAIs[i].getClass().toString());
		}
	}
	
	private static URLClassLoader	loader;
	private static boolean			loadFailed	= false;
	private static Class<?>[]		loadedAIs;
	private static String[]			loadedAINames;
	
	private static void loadAIs() {
		ArrayList<String> classNames = findClassesToLoad();
		if (!loadFailed) {
			ArrayList<Class<?>> aiClasses = new ArrayList<Class<?>>();
			for (int i = 0; i < classNames.size(); i++) {
				String className = classNames.get(i);
				Class<?> potentialAI = tryLoadClass(className);
				if (potentialAI != null) {
					if (AI.class.isAssignableFrom(potentialAI)) {
						aiClasses.add(potentialAI);
					} else {
						System.out.println("Class is not an AI: " + className);
					}
				}
			}
			loadedAIs = new Class<?>[aiClasses.size()];
			loadedAINames = new String[aiClasses.size()];
			for (int i = 0; i < aiClasses.size(); i++) {
				loadedAIs[i] = aiClasses.get(i);
				loadedAINames[i] = loadedAIs[i].getSimpleName();
			}
			
		} else {
			System.err.println("Unable to locate AI folder and Classes");
		}
	}
	
	private static ArrayList<String> findClassesToLoad() {
		File aiFolder = new File(LOAD_PATH + "\\" + LOAD_PACKAGE);
		File[] listOfFiles = aiFolder.listFiles();
		
		
		ArrayList<String> classNames = new ArrayList<String>();
		for (File file : listOfFiles) {
			if (file.isFile()) {
				String name = file.getName();
				if (name.endsWith(".class")) {
					classNames.add(name.substring(0, name.length() - 6));
				} else {
					System.out.println("Non Class file in \"" + LOAD_PATH + "\": " + name);
				}
			}
		}
		
		return classNames;
	}
	
	private static Class<?> tryLoadClass(String className) {
		if (loader == null) {
			try {
				loader = new URLClassLoader(new URL[] { Paths.get(LOAD_PATH).toUri().toURL() });
			} catch (MalformedURLException e) {
				System.out.println("Malformed URL");
			}
		}
		
		try {
			return loader.loadClass(LOAD_PACKAGE + "." + className);
		} catch (ClassNotFoundException e) {
			System.err.println("Could not load Class: " + className);
			return null;
		}
//			catch (NoClassDefFoundError e) {
//			System.err.println("No Class definition found: " + className);
//			return null;
//		}
	}
	
	public static String[] getLoadedAIs() {
		if (loadedAIs == null) {
			loadAIs();
		}
		
		return loadedAINames;
	}
	
	public static AI newInstanceOf(int index) {
		AI instance = null;
		try {
			instance = (AI) loadedAIs[index].newInstance();
		} catch (InstantiationException e) {
			System.err.println("Can not instatiate Class: " + loadedAINames[index]);
		} catch (IllegalAccessException e) {
			System.err.println("Can not acces Class constructor: " + loadedAINames[index]);
		}
		
		return instance;
	}
	
}
